package simple.flow.config.log;

import cn.hutool.json.JSONUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import simple.flow.util.IpUtil;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Enumeration;

/**
 * 接口请求日志
 *
 * @author lhd
 * @since 2025/4/10 17:45
 */

@Aspect
@Component
public class ApiLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(ApiLogAspect.class);

    @Around("@annotation(simple.flow.config.log.ApiLog) || " +
            "@annotation(org.springframework.web.bind.annotation.PostMapping) || " +
            "@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();

            StringBuilder requestLog = new StringBuilder();
            requestLog.append("\n======================== Request Start ========================\n");
            // 记录请求方法和 URL
            requestLog.append("HTTP Method:\t").append(request.getMethod()).append("\n");
            // 获取请求信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            requestLog.append("Class Method:\t").append(method.getName()).append("\n");
            requestLog.append("URL:\t").append(request.getRequestURL().toString()).append("\n");
            requestLog.append("IP:\t\t").append(IpUtil.getIpAddr(request)).append("\n");
            // 打印请求头（可选）
            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                String headerName = headerNames.nextElement();
                requestLog.append("Header:\t").append(headerName).append(" = ").append(request.getHeader(headerName)).append("\n");
            }

            requestLog.append("Request Args:\t").append(JSONUtil.toJsonPrettyStr(joinPoint.getArgs())).append("\n");



            long startTime = System.currentTimeMillis();
            Object result;
            try {
                // 执行目标方法
                result = joinPoint.proceed();
            } catch (Throwable throwable) {
                // 异常处理
                long costTime = System.currentTimeMillis() - startTime;
                logger.error("{}\n======================== Request Error ========================\nException     : {}\nCost Time     : {} ms\n======================== Request End ========================", requestLog, throwable.getMessage(), costTime);
                throw throwable;
            }

            // 计算耗时
            long costTime = System.currentTimeMillis() - startTime;

            // 构建响应日志
            String responseJson = JSONUtil.toJsonPrettyStr(result);
            logger.info("{}\n======================== Response ========================\nResponse Args : {}\nCost Time     : {} ms\n======================== Request End ========================\n", requestLog.toString(), responseJson, costTime);

            return result;

        }

        return null;
    }
}
